using System.Collections.Generic;
using UnityEngine;

public class PlayerControlJnR : MonoBehaviour
{
    public MovementDirection CurrentDirection;
    public float JumpForce = 4f, MaxSpeed = 7.5f;

    private float inputVelocity;

    private bool jump;
    private int jumpCount;
    private float jumpVelocity;
    private string[] keybindings;
    private List<CollisionSide> lockedSide;
    private bool move;
    private bool usePowerup;
    private float velocity;
    private bool wallJump;
    private string wallJumpSide;

    private void Start()
    {
        EventManager.OnInput += EventManagerOnInput;
        EventManager.OnCollision += EventManagerOnCollision;

        this.jump = false;
        this.move = false;
        this.usePowerup = false;
        this.jumpCount = 0;
        this.jumpVelocity = 0;
        this.inputVelocity = 0;
        this.velocity = 0;
        this.wallJumpSide = "none";
        this.lockedSide = new List<CollisionSide>();

        UserSettings settings = new UserSettings();
        this.keybindings = settings.loadKeybindings();
        if (this.keybindings.Length < 3)
        {
            this.keybindings = new string[3];
            this.keybindings[0] = "RightArrow";
            this.keybindings[1] = "LeftArrow";
            this.keybindings[2] = "Space";
        }
    }

    private void Update()
    {
        CalculateMovementSpeed(this.inputVelocity);

        CalculateJumpVelocity();

        rigidbody.velocity = new Vector3(this.velocity, this.jumpVelocity, 0);

        CombatAbilities();
    }

    private void OnDestroy()
    {
        EventManager.OnCollision -= EventManagerOnCollision;
        EventManager.OnInput -= EventManagerOnInput;
    }

    private void EventManagerOnCollision(object sender, CollisionEventArgs collisionEventArgs)
    {
        CollisionType collisionType = collisionEventArgs.CollisionType;
        switch (collisionType)
        {
            case CollisionType.Enter:
                switch (collisionEventArgs.CollisionSide)
                {
                    case CollisionSide.Down:
                        this.jumpCount = 0;
                        if (this.jumpVelocity < 0)
                            this.jumpVelocity = 0;
                        this.wallJumpSide = "none";
                        rigidbody.useGravity = true;
                        break;
                    case CollisionSide.Up:
                        if (this.jumpVelocity > 0)
                            this.jumpVelocity = 0;
                        this.wallJumpSide = "none";
                        break;
                    case CollisionSide.Left:
                        this.wallJumpSide = "left";
                        this.lockedSide.Add(CollisionSide.Left);
                        break;
                    case CollisionSide.Right:
                        this.wallJumpSide = "right";
                        this.lockedSide.Add(CollisionSide.Right);
                        break;
                    case CollisionSide.None:
                        this.wallJumpSide = "none";
                        break;
                }
                break;
            case CollisionType.Exit:
                switch (collisionEventArgs.CollisionSide)
                {
                    case CollisionSide.Down:
                        rigidbody.useGravity = true;
                        break;
                    case CollisionSide.Left:
                        this.wallJump = false;
                        lockedSide.Remove(CollisionSide.Left);
                        break;
                    case CollisionSide.Right:
                        this.wallJump = false;
                        lockedSide.Remove(CollisionSide.Right);
                        break;
                }
                this.wallJumpSide = "none";
                break;
            case CollisionType.Stay:
                break;
            case CollisionType.None:
                break;
        }
    }

    private void EventManagerOnInput(object sender, List<InputEventArgs> inputEventArgs)
    {
        foreach (InputEventArgs currentInput in inputEventArgs)
        {
            switch (currentInput.Device)
            {
                case InputDevice.XboxController:

                    #region xbox

                    switch (currentInput.Type)
                    {
                        case InputType.LAnalog:
                            if (currentInput.Input.Contains("h"))
                            {
                                float rawVelocity = float.Parse(currentInput.Input.Replace("h", ""));
                                this.inputVelocity = rawVelocity;
                                if (rawVelocity != 0 && !this.move)
                                    this.move = true;
                                else
                                    this.move = false;
                            }
                            break;
                        case InputType.Down:
                            if (currentInput.Input == "A")
                            {
                                if (this.jumpCount < 2)
                                    this.jump = true;
                                if (this.wallJumpSide != "none")
                                    this.wallJump = true;
                            }
                            break;
                    }

                    #endregion

                    break;
                case InputDevice.Keyboard:

                    #region keyboard

                    switch (currentInput.Type)
                    {
                        case InputType.Down:
                            this.move = true;
                            if (currentInput.Input == this.keybindings[0])
                            {
                                this.inputVelocity = 1;
                            }
                            else if (currentInput.Input == this.keybindings[1])
                            {
                                this.inputVelocity = -1;
                            }
                            else if (currentInput.Input == this.keybindings[2])
                            {
                                if (this.jumpCount < 2)
                                    this.jump = true;
                                if (this.wallJumpSide != "none")
                                    this.wallJump = true;
                            }
                            else if (currentInput.Input == "P")
                            {
                                this.usePowerup = true;
                            }
                            break;
                        case InputType.Up:
                            this.move = false;
                            if (currentInput.Input == this.keybindings[0] || currentInput.Input == this.keybindings[1])
                            {
                                this.inputVelocity = 0;
                            }
                            break;
                    }

                    #endregion

                    break;
                case InputDevice.Ps3Controller:

                    #region ps3

                    #endregion

                    break;
            }
        }
    }

    private void CalculateMovementSpeed(float rawVelocity)
    {
        //TODO: Max Speed aus Klasse Player
        //float maxSpeed = Player.MaxMovementSpeed;
        //float tempMaxSpeed = Player.MaxMovementSpeed / 2;

        float maxSpeed = this.MaxSpeed;
        float tempMaxSpeed = this.MaxSpeed / 2;

        if (rawVelocity < 0)
        {
            if (!this.lockedSide.Contains(CollisionSide.Left))
            {
                if (rawVelocity > -0.5f)
                {
                    if (this.velocity > -tempMaxSpeed)
                        this.velocity -= 0.5f;
                    else
                        this.velocity = -tempMaxSpeed;
                }
                else if (rawVelocity <= -0.5f)
                {
                    if (this.velocity > -maxSpeed)
                        this.velocity--;
                    else
                        this.velocity = -maxSpeed;
                }
                this.CurrentDirection = MovementDirection.Left;
            }
            else
            {
                velocity = 0;
            }
        }
        else if (rawVelocity > 0)
        {
            if (!this.lockedSide.Contains(CollisionSide.Right))
            {
                if (rawVelocity < 0.5f)
                {
                    if (this.velocity < tempMaxSpeed)
                        this.velocity += 0.5f;
                    else
                        this.velocity = tempMaxSpeed;
                }
                else if (rawVelocity >= 0.5f)
                {
                    if (this.velocity < maxSpeed)
                        this.velocity++;
                    else
                        this.velocity = maxSpeed;
                }
                this.CurrentDirection = MovementDirection.Right;
            }
            else
            {
                velocity = 0;
            }
        }
        else if (rawVelocity == 0)
        {
            NormalizeVelocity();
            //currentDirection = MovementDirection.Idle;
        }
    }

    private void NormalizeVelocity()
    {
        if (this.velocity > 1.5f)
            this.velocity -= 1;
        else if (this.velocity >= 0.1f)
            this.velocity -= 0.1f;
        else if (this.velocity <= -1.5f)
            this.velocity += 1;
        else if (this.velocity <= -0.1f)
            this.velocity += 0.1f;
        else
            this.velocity = 0;
    }

    private void CalculateJumpVelocity()
    {
        this.jumpVelocity = rigidbody.velocity.y;

        if (this.jump)
        {
            this.jumpVelocity = this.JumpForce;
            this.jumpCount++;
            this.jump = false;
        }

        if (this.wallJump)
        {
            this.jumpVelocity = this.JumpForce * 1.5f;
            switch (this.wallJumpSide)
            {
                case "left":
                    this.velocity = Player.MaxMovementSpeed * 1.25f;
                    break;
                case "right":
                    this.velocity = -Player.MaxMovementSpeed * 1.25f;
                    break;
            }
            lockedSide.Remove(CollisionSide.Left);
            lockedSide.Remove(CollisionSide.Right);
            this.wallJump = false;
        }
    }

    private void CombatAbilities()
    {
        //TODO: Attack, Block, etc.
        if (this.usePowerup)
        {
            Player.Powerup.Activate();
            this.usePowerup = false;
        }
    }
}